//! macOS os_log Appender
//!
//! 将 FATAL 级别日志写入 macOS os_log。
//!
//! ## 功能
//!
//! - 使用 oslog crate 的 os_log API
//! - 设置 subsystem 标识应用来源
//! - 同步写入确保进程崩溃前完成
//!
//! ## 示例
//!
//! ```rust,ignore
//! use log4r::appender::syslog::macos::OsLogAppender;
//! use log4r::appender::syslog::SyslogAppender;
//! use log4r::{LogEvent, Level};
//!
//! let appender = OsLogAppender::new("my_app");
//! let event = LogEvent::new(Level::Fatal, "my_app", "严重错误");
//! appender.write_syslog(&event).ok();
//! ```

use oslog::OsLog;

use crate::error::Log4rError;
use crate::event::LogEvent;

use super::SyslogAppender;

/// macOS os_log Appender
///
/// 将 FATAL 级别日志写入 macOS os_log。
/// 使用 subsystem 标识应用来源。
///
/// ## 线程安全
///
/// `OsLogAppender` 实现 `Send + Sync`，可以安全地在线程间共享。
/// - `subsystem` 是 `String`，本身是 `Send + Sync`
/// - `category` 是 `String`，本身是 `Send + Sync`
/// - 没有内部可变状态
///
/// ## 示例
///
/// ```rust,ignore
/// use log4r::appender::syslog::macos::OsLogAppender;
/// use log4r::appender::syslog::SyslogAppender;
///
/// let appender = OsLogAppender::new("my_app");
/// assert_eq!(appender.name(), "OsLogAppender");
/// ```
pub struct OsLogAppender {
    /// 日志子系统（app_name）
    subsystem: String,
    /// 日志类别
    category: String,
}

impl OsLogAppender {
    /// 创建新的 macOS os_log Appender
    ///
    /// # Arguments
    ///
    /// * `app_name` - 应用名称，用作 subsystem
    ///
    /// # Returns
    ///
    /// 返回新的 `OsLogAppender` 实例
    ///
    /// # 示例
    ///
    /// ```rust,ignore
    /// use log4r::appender::syslog::macos::OsLogAppender;
    ///
    /// let appender = OsLogAppender::new("my_app");
    /// ```
    pub fn new(app_name: &str) -> Self {
        Self {
            subsystem: app_name.to_string(),
            category: "fatal".to_string(),
        }
    }

    /// 获取 subsystem
    ///
    /// # Returns
    ///
    /// 返回 subsystem 的引用
    pub fn subsystem(&self) -> &str {
        &self.subsystem
    }

    /// 格式化日志消息
    ///
    /// 格式: `{timestamp} [{level}] {target}: {message}`
    ///
    /// # Arguments
    ///
    /// * `event` - 日志事件
    ///
    /// # Returns
    ///
    /// 格式化后的消息字符串
    fn format_message(&self, event: &LogEvent) -> String {
        // 使用 RFC3339 格式化时间戳，失败时使用默认格式
        let timestamp = event
            .timestamp
            .format(&time::format_description::well_known::Rfc3339)
            .unwrap_or_else(|_| event.timestamp.to_string());

        format!(
            "{} [{}] {}: {}",
            timestamp, event.level, event.target, event.message
        )
    }
}

impl SyslogAppender for OsLogAppender {
    /// 同步写入 macOS os_log
    ///
    /// # Arguments
    ///
    /// * `event` - 要写入的日志事件
    ///
    /// # Returns
    ///
    /// * `Ok(())` - 写入成功
    /// * `Err(Log4rError::AppenderError)` - 写入失败
    ///
    /// # 日志级别映射
    ///
    /// FATAL 级别映射到 OS_LOG_TYPE_FAULT
    fn write_syslog(&self, event: &LogEvent) -> Result<(), Log4rError> {
        // 验证 subsystem 非空
        if self.subsystem.is_empty() {
            return Err(Log4rError::AppenderError {
                name: "OsLogAppender".to_string(),
                cause: "app_name 不能为空".to_string(),
            });
        }

        let message = self.format_message(event);

        // 创建 OsLog 实例并使用 fault 级别写入
        // fault 是最高严重级别，对应 FATAL (OS_LOG_TYPE_FAULT)
        let log = OsLog::new(&self.subsystem, &self.category);
        log.with_level(oslog::Level::Fault, &message);

        Ok(())
    }

    fn name(&self) -> &'static str {
        "OsLogAppender"
    }
}

// OsLogAppender 是 Send + Sync 安全的
// - subsystem 和 category 是 String，本身是 Send + Sync
// - 没有内部可变状态
// - OsLog 在每次写入时创建，无需存储
unsafe impl Send for OsLogAppender {}
unsafe impl Sync for OsLogAppender {}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::level::Level;

    // UT-8.3-001: 测试 OsLogAppender::new() 创建 (AC: 8.3.2)
    #[test]
    fn test_oslog_appender_new() {
        // GIVEN: 应用名称
        let app_name = "test_app";

        // WHEN: 创建 OsLogAppender
        let appender = OsLogAppender::new(app_name);

        // THEN: subsystem 应正确设置
        assert_eq!(appender.subsystem(), "test_app");
    }

    // UT-8.3-002: 测试消息格式化包含所有字段 (AC: 8.3.4)
    #[test]
    fn test_format_message_contains_all_fields() {
        // GIVEN: OsLogAppender 和 LogEvent
        let appender = OsLogAppender::new("my_app");
        let event = LogEvent::new(Level::Fatal, "my_app::module", "严重错误消息");

        // WHEN: 格式化消息
        let message = appender.format_message(&event);

        // THEN: 消息应包含所有字段
        // 格式: {timestamp} [{level}] {target}: {message}
        assert!(message.contains("[FATAL]"), "应包含级别: {}", message);
        assert!(
            message.contains("my_app::module"),
            "应包含 target: {}",
            message
        );
        assert!(message.contains("严重错误消息"), "应包含消息: {}", message);
        // 时间戳应为 RFC3339 格式（包含 T 和时区）
        assert!(
            message.contains("T") || message.contains("-"),
            "应包含时间戳: {}",
            message
        );
    }

    // UT-8.3-003: 测试日志级别为 fault (AC: 8.3.3)
    #[test]
    fn test_level_is_fault() {
        // GIVEN: oslog::Level::Fault
        // WHEN: 检查值
        // THEN: Level::Fault 对应 OS_LOG_TYPE_FAULT
        // oslog 的 Level::Fault 是最高严重级别
        let level = oslog::Level::Fault;
        // 编译通过即验证 Level::Fault 存在
        assert!(matches!(level, oslog::Level::Fault));
    }

    // UT-8.3-004: 测试 SyslogAppender trait 实现 (AC: 8.3.1)
    #[test]
    fn test_syslog_appender_trait_implementation() {
        // GIVEN: OsLogAppender
        let appender = OsLogAppender::new("test_app");

        // WHEN: 调用 trait 方法
        let name = appender.name();

        // THEN: 应返回正确的名称
        assert_eq!(name, "OsLogAppender");
    }

    // UT-8.3-005: 测试 OsLogAppender 是 Send + Sync
    #[test]
    fn test_oslog_appender_is_send_sync() {
        // GIVEN: OsLogAppender
        // WHEN: 检查 Send + Sync
        // THEN: 编译通过即验证成功
        fn assert_send<T: Send>() {}
        fn assert_sync<T: Sync>() {}

        assert_send::<OsLogAppender>();
        assert_sync::<OsLogAppender>();
    }

    // UT-8.3-006: 测试 subsystem 字段正确设置 (AC: 8.3.2)
    #[test]
    fn test_subsystem_field() {
        // GIVEN: 应用名称
        let app_name = "log4r_test_app";
        let appender = OsLogAppender::new(app_name);

        // THEN: subsystem 应与 app_name 一致
        assert_eq!(appender.subsystem(), app_name);
    }

    // UT-8.3-007: 测试空应用名称创建成功
    #[test]
    fn test_empty_app_name() {
        // GIVEN: 空应用名称
        let appender = OsLogAppender::new("");

        // THEN: 创建应成功
        assert_eq!(appender.subsystem(), "");
    }

    // UT-8.3-008: 测试空应用名称写入时返回错误
    #[test]
    fn test_empty_app_name_write_returns_error() {
        // GIVEN: 空应用名称的 Appender
        let appender = OsLogAppender::new("");
        let event = LogEvent::new(Level::Fatal, "test", "测试消息");

        // WHEN: 尝试写入
        let result = appender.write_syslog(&event);

        // THEN: 应返回错误
        assert!(result.is_err());
        if let Err(err) = result {
            assert!(err.to_string().contains("app_name"));
        }
    }

    // UT-8.3-009: 测试 Unicode 应用名称
    #[test]
    fn test_unicode_app_name() {
        // GIVEN: Unicode 应用名称
        let appender = OsLogAppender::new("日志应用");

        // THEN: 应正确保存
        assert_eq!(appender.subsystem(), "日志应用");
    }

    // UT-8.3-010: 测试消息格式化 Unicode 内容
    #[test]
    fn test_format_message_unicode() {
        // GIVEN: Unicode 内容的 LogEvent
        let appender = OsLogAppender::new("测试");
        let event = LogEvent::new(Level::Fatal, "日志::模块", "错误消息 🚀");

        // WHEN: 格式化消息
        let message = appender.format_message(&event);

        // THEN: Unicode 应正确保存
        assert!(message.contains("日志::模块"));
        assert!(message.contains("🚀"));
    }

    // 注意：实际的 os_log 写入测试需要在 macOS 系统上运行
    // 因此标记为 #[ignore]
    #[test]
    #[ignore]
    fn test_write_syslog_integration() {
        // GIVEN: OsLogAppender 和 FATAL 事件
        let appender = OsLogAppender::new("log4r_test");
        let event = LogEvent::new(Level::Fatal, "log4r::test", "集成测试消息");

        // WHEN: 写入系统日志
        let result = appender.write_syslog(&event);

        // THEN: 应成功（在 macOS 上）
        println!("写入结果: {:?}", result);
    }
}
